package com.gmcloud.gateway.filter;

import cn.hutool.core.text.CharSequenceUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gmcloud.common.core.constant.SecurityConstants;
import com.gmcloud.common.core.exception.ValidateCodeException;
import com.gmcloud.common.utils.R;
import com.gmcloud.gateway.config.GatewayConfigProperties;
import com.gmcloud.plugin.captcha.model.ResponseModel;
import com.gmcloud.plugin.captcha.service.CaptchaService;
import com.gmcloud.plugin.captcha.service.CaptchaServiceFactory;
import com.gmcloud.plugin.captcha.vo.CaptchaVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import com.gmcloud.common.core.utils.WebUtil;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * @author zl.sir
 * @version 1.0
 * @since 2022/8/15 18:25
 * 验证码处理
 */
@Component
public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory<Object> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ValidateCodeGatewayFilter.class);
    private final GatewayConfigProperties configProperties;

    private final ObjectMapper objectMapper;


    public ValidateCodeGatewayFilter(GatewayConfigProperties configProperties, ObjectMapper objectMapper) {
        this.configProperties = configProperties;
        this.objectMapper = objectMapper;
    }

    @Override
    public GatewayFilter apply(Object config) {
        return ((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
//            是否是登录 ······················验证地址
            boolean isAuthToken = CharSequenceUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL);

            if (!isAuthToken) {
                //不是登录放行
                return chain.filter(exchange);
            }
            // 刷新token，手机号登录（也可以这里进行校验） 直接向下执行
            String grantType = request.getQueryParams().getFirst("grant_type");
            if (CharSequenceUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
                return chain.filter(exchange);
            }
            // 白名单客户端
            boolean isIgnoreClient = configProperties.getIgnoreClients().contains(WebUtil.getClientId(request));

            try {

                // only oauth and the request not in ignore clients need check code.
                if (!isIgnoreClient) {
                    checkCode(request);
                }
            } catch (Exception e) {
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
                response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

                final String errMsg = e.getMessage();
                return response.writeWith(Mono.create(monoSink -> {
                    try {
                        byte[] bytes = objectMapper.writeValueAsBytes(R.failed(errMsg));
                        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);

                        monoSink.success(dataBuffer);
                    } catch (JsonProcessingException jsonProcessingException) {
                        LOGGER.error("对象输出异常", jsonProcessingException);
                        monoSink.error(jsonProcessingException);
                    }
                }));
            }

            return chain.filter(exchange);
        });
    }

    /**
     * 检查验证码
     *
     * @param request 请求
     * @throws Exception 异常
     */

    private void checkCode(ServerHttpRequest request) throws Exception {
        String captchaVerification = request.getQueryParams().getFirst("captchaVerification");

        if (CharSequenceUtil.isBlank(captchaVerification)) {
            throw new ValidateCodeException("captchaVerification验证码不能为空");
        }
        String captchaType=request.getQueryParams().getFirst("captchaType");

//      二次验证
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(captchaVerification);
        CaptchaService captchaService= CaptchaServiceFactory.instances.get(captchaType);
        ResponseModel responseModel = captchaService.verification(captchaVO);
        if (!responseModel.isSuccess()) {
            throw new ValidateCodeException(responseModel.getMessage());
        }
//        String randomStr = request.getQueryParams().getFirst("randomStr");
//        if (CharSequenceUtil.isBlank(randomStr)) {
//            randomStr = request.getQueryParams().getFirst("mobile");
//        }
//
//        String key = CacheConstants.DEFAULT_CODE_KEY + randomStr;
//        Object codeObj = redisUtils.get(key);
//        redisUtils.del(Collections.singletonList(key));
//        if (code == null || ObjectUtil.isEmpty(codeObj) || !code.equals(codeObj)) {
//            throw new ValidateCodeException("验证码不合法");
//        }
    }
}
